// server-side game logic for a texas hold 'em game
const Deck = require('./deck.js');
const Player = require('./player.js');
const Hand = require('./classes/pokersolver.js').Hand;

const Game = function (name, host) {
  this.stop = false
  this.deck = new Deck();
  this.host = host;
  this.allplayers=[];
  this.players = [];
  this.status = 0;
  this.cardsPerPlayer = 2;
  this.currentlyPlayed = 0;
  this.gameWinner = null;
  this.gameName = name;
  this.roundNum = 0;
  this.start = false;
  this.roundData = {
    dealer: 0,
    bigBlind: '',
    smallBlind: '',
    turn: '',
    bets: [],
  };
  this.community = [];
  this.foldPot = 0;
  this.bigBlindWent = false;
  this.lastMoveParsed = { move: '', player: '' };
  this.roundInProgress = false;
  // this.disconnectedPlayers = [];
  this.autoBuyIns = true;
  this.debug = false;
  this.smallBlind = 10;
  this.bigBlind = 20;
  this.waitcheckfold = [];
  this.waitcall = [];

  const constructor = (function () {})(this);

  this.log = () => {
    if (this.debug) {
      console.log(...arguments);
    }
  };

  this.assignBlind = () => {
    this.roundData.smallBlind =
        this.roundData.dealer + 1 < this.players.length
            ? this.roundData.dealer + 1
            : 0;
    this.roundData.bigBlind =
        this.roundData.smallBlind + 1 < this.players.length
            ? this.roundData.smallBlind + 1
            : 0;

    this.log('smallBlind: ' + this.roundData.smallBlind);
    this.log('bigBlind: ' + this.roundData.bigBlind);

    for (let i = 0; i < this.players.length; i++) {
      this.players[i].setDealer(i === this.roundData.dealer);
      if (i === this.roundData.bigBlind) {
        this.players[i].setBlind('Big Blind');
      } else if (i === this.roundData.smallBlind) {
        this.players[i].setBlind('Small Blind');
      } else {
        this.players[i].setBlind('');
      }
      this.players[i].setStatus('');
    }

    const goFirstIndex =
        this.roundData.bigBlind + 1 >= this.players.length
            ? 0
            : this.roundData.bigBlind + 1;
    this.roundData.turn = this.players[goFirstIndex].getUsername();
    this.players[goFirstIndex].setStatus('Their Turn');
    this.EmitQuickQcheckOrFold();
    this.EmitQuickCall();
  };
  this.startGame = () => {
    this.emitallPlayers('startGame', {
      players: this.allplayers.map((p) => {
        return p.username;
      }),
    });
  };
  this.findallPlayer = (socketId) => {
    for (let pn = 0; pn < this.getNumallPlayers(); pn++) {
      if (this.allplayers[pn].socket.id === socketId) {
        return this.allplayers[pn];
      }
    }
    return { socket: { id: 0 } };
  };
  this.findPlayer = (socketId) => {
    for (let pn = 0; pn < this.getNumPlayers(); pn++) {
      if (this.players[pn].socket.id === socketId) {
        return this.players[pn];
      }
    }
    return { socket: { id: 0 } };
  };

  this.addPlayer = (playerName, socket) => {
    const player = new Player(playerName, socket, this.debug);
    this.allplayers.push(player);
    return player;
  };
  this.getNumPlayers = () => {
    return this.players.length;
  };
  this.getNumallPlayers = () => {
    return this.allplayers.length;
  };
  this.PlayerSitDown = (socket) =>{
    const player = this.findallPlayer(socket.id);
    let currTurnIndex = this.allplayers.findIndex(
        (p) => p === player
    );
    this.allplayers[currTurnIndex].disconnected = 0;
    this.rerender();
  }
  this.PlayerStandUp = (socket) =>{
    const player = this.findallPlayer(socket.id);
    let currTurnIndex = this.allplayers.findIndex(
        (p) => p === player
    );
    this.allplayers[currTurnIndex].disconnected = 1;
  }
  this.emitPlayers = (eventName, payload) => {
    for (let pn = 0; pn < this.getNumPlayers(); pn++) {
      this.players[pn].emit(eventName, payload);
    }
  };
  this.emitallPlayers = (eventName, payload) => {
    for (let pn = 0; pn < this.getNumallPlayers(); pn++) {
      this.allplayers[pn].emit(eventName, payload);
    }
  };
  this.pushplayers = () =>{
    this.players=this.allplayers.filter(
        (p) => p.disconnected == 0);
  }

  this.buyInfree = (socket) =>{
    const player = this.findPlayer(socket.id);
    player.buyInwaitting ++
  }
  this.stopgame = ()=>{
    this.stop = true
  }
  this.startNewRound = () => {
    console.log('开始游戏')
    if (!this.stop) {
      if (this.players.length > 1) {
        if (this.roundNum == 0) {
          setTimeout(() => this.stopgame(), 3600000);

          this.emitallPlayers('startclock', {});
        }
        this.lastMoveParsed = {move: '', player: ''};
        this.roundInProgress = true;
        this.foldPot = 0;
        this.bigBlindWent = false;
        this.community = [];
        this.roundData.turn = '';
        this.roundData.bets = [];
        this.waitcheckfold = [];
        this.flopcard = 0
        this.dealCards();
        this.log('deck len' + this.deck.cards.length);
        for (player of this.players) {
          if (player.getBuyInwaitting() > 0) {
            player.money = player.money + Number(player.getBuyInwaitting()) * 500;
            player.buyIns = player.buyIns + Number(player.getBuyInwaitting());
            player.buyInwaitting = 0
          }
        }
        for (pn of this.players) {
          pn.allIn = false;
        }

        // Init dealer
        if (this.roundNum == 0) {
          this.roundData.dealer = 0;
        } else {
          this.roundData.dealer =
              this.roundData.dealer + 1 < this.players.length
                  ? this.roundData.dealer + 1
                  : 0;
        }
        // Init blind and first player
        this.assignBlind();

        if (this.autoBuyIns) {
          for (player of this.players) {
            if (player.getMoney() <= 0) {
              for (let i = 0; 1 < 10; i++) {
                player.money = player.money + 500;
                player.buyIns = player.buyIns + 1;
                if (player.money >= 500) {
                  break;
                }
              }
            }
          }
        }

        // handle big and small blind initial forced bets

        if (this.players[this.roundData.bigBlind].money < this.bigBlind) {
          this.players[this.roundData.bigBlind].money = 0;
          this.players[this.roundData.bigBlind].allIn = true;
          this.roundData.bets.push([
            {
              player: this.players[this.roundData.bigBlind].getUsername(),
              bet: this.players[this.roundData.bigBlind].money,
            },
          ]);
        } else {
          this.players[this.roundData.bigBlind].money =
              this.players[this.roundData.bigBlind].money - this.bigBlind;
          this.roundData.bets.push([
            {
              player: this.players[this.roundData.bigBlind].getUsername(),
              bet: this.bigBlind,
            },
          ]);
        }

        if (this.players[this.roundData.smallBlind].money < this.smallBlind) {
          this.players[this.roundData.smallBlind].money = 0;
          this.roundData.bets[0].push({
            player: this.players[this.roundData.smallBlind].getUsername(),
            bet: this.players[this.roundData.bigBlind].money,
          });
          this.players[this.roundData.smallBlind].allIn = true;
        } else {
          this.players[this.roundData.smallBlind].money =
              this.players[this.roundData.smallBlind].money - this.smallBlind;
          this.roundData.bets[0].push({
            player: this.players[this.roundData.smallBlind].getUsername(),
            bet: this.smallBlind,
          });
        }
        this.roundNum++;
        this.timecooldown();
        this.rerender();
        console.log('开始第' + this.roundNum + '局游戏')
      } else {
        this.emitPlayers('notenoughplayers', {})
        console.log('玩家数量不足，当前玩家数：' + this.players.length)
      }
    }else{
      this.emitPlayers('stopgame', {})
      console.log('游戏结束')

    }
  };

  this.rerender = () => {
    for (let i = 0 ; i< this.getNumallPlayers(); i++){
      for (let pn = 0; pn < this.getNumPlayers(); pn++){
        if (this.allplayers[i].getUsername()==this.players[pn].getUsername()){
          this.allplayers[i].money = this.players[pn].money;
          this.allplayers[i].buyIns = this.players[pn].buyIns;
          this.allplayers[i].blindValue = this.players[pn].blindValue;
          this.allplayers[i].status=this.players[pn].status;
        }
      }
    }
    let playersData = [];
    let playerDataforone = [];
    for (let pn = 0; pn < this.getNumPlayers(); pn++) {
      playersData.push({
        index:pn,
        username: this.players[pn].getUsername(),
        status: this.players[pn].getStatus(),
        blind: this.players[pn].getBlind(),
        money: this.players[pn].getMoney(),
        buyIns: this.players[pn].buyIns,
        isChecked: this.playerIsChecked(this.players[pn]),
      });
    }
    let result = [];
    for (let pn = 0; pn < this.getNumallPlayers(); pn++) {
      result.push({
        username: this.allplayers[pn].getUsername(),
        gain: this.allplayers[pn].getMoney()-500-500*this.allplayers[pn].buyIns,
      });
    }
    let ontable = [];
    for (let pn = 0; pn < this.getNumallPlayers(); pn++) {
      if (this.allplayers[pn].disconnected == 0 && !this.players.includes(this.allplayers[pn])) {
        ontable.push(this.allplayers[pn].getUsername());
      }
    }
    result = result.sort((a, b) =>
        a.gain < b.gain ? 1 : -1
    );
    for (let pn = 0; pn < this.getNumPlayers(); pn++) {
      playerDataforone = playersData.filter((p) => p.index != pn)
      for (let i = 0; i < playerDataforone.length; i++) {
        if (playerDataforone[i].index < pn) playerDataforone[i].index += this.players.length;
      }
      playerDataforone = playerDataforone.sort((a, b) => a.index < b.index ? -1 : 1)
      this.players[pn].emit('rerender', {
        community: this.community,
        topBet: this.getCurrentTopBet(),
        bets: this.roundData.bets,
        username: this.players[pn].getUsername(),
        round: this.roundNum,
        stage: this.getStageName(),
        pot: this.getCurrentPot(),
        players: playerDataforone,
        myMoney: this.players[pn].getMoney(),
        myBet: this.getPlayerBetInStage(this.players[pn]),
        myStatus: this.players[pn].getStatus(),
        myBlind: this.players[pn].getBlind(),
        roundInProgress: this.roundInProgress,
        buyIns: this.players[pn].buyIns,
        results: result,
      });
    }
    for (let pn = 0; pn < this.getNumallPlayers(); pn++) {
      if (!this.players.includes(this.allplayers[pn])) {
        this.allplayers[pn].emit('rerender', {
          community: this.community,
          topBet: this.getCurrentTopBet(),
          bets: this.roundData.bets,
          username: this.allplayers[pn].getUsername(),
          round: this.roundNum,
          stage: this.getStageName(),
          pot: this.getCurrentPot(),
          players: playersData,
          myMoney: this.allplayers[pn].getMoney(),
          myBet: this.getPlayerBetInStage(this.allplayers[pn]),
          myStatus: this.allplayers[pn].getStatus(),
          myBlind: this.allplayers[pn].getBlind(),
          roundInProgress: this.roundInProgress,
          buyIns: this.allplayers[pn].buyIns,
          results: result,
        });
      }
    }
    for (let pn = 0; pn < this.getNumallPlayers(); pn++) {
      if (!this.players.includes(this.allplayers[pn]))
        this.allplayers[pn].emit('waitname', {
          waitplayer:ontable,
        });
    }
  };
  this.findName = (name) => {
    for (let pn = 0; pn < this.getNumallPlayers(); pn++) {
      if (this.allplayers[pn].getUsername()== name) {
        return this.allplayers[pn];
      }
    }
  };

  this.dealwithdisconnectwhenallin = () =>{
    if(this.roundData.bets.length = 1) {
      do {
        this.community.push(this.deck.dealRandomCard());
        this.flopcard ++
      }
      while (this.flopcard < 5)
    }
    if (this.roundData.bets.length >1) {
      do {
        this.community.push(this.deck.dealRandomCard());
        this.roundData.bets.push([]);
      }
      while (this.roundData.bets.length < 4)
    }
  }
  this.callbackfordisconnect = () =>{
    if (this.flopcard == 5) {
      this.rerender();
      const roundResults = this.evaluateWinners();
      for (playerResult of roundResults.playersData) {
        playerResult.player.setStatus(playerResult.hand.name);
      }
      const winningData = this.distributeMoney(roundResults);
      this.revealCards(winningData.filter((a) => a.winner));
    }
    if (this.roundData.bets.length == 4) {
      this.rerender();
      const roundResults = this.evaluateWinners();
      for (playerResult of roundResults.playersData) {
        playerResult.player.setStatus(playerResult.hand.name);
      }
      const winningData = this.distributeMoney(roundResults);
      this.revealCards(winningData.filter((a) => a.winner));//命令能发送，能分配输赢，但是不能出现文本
    }
  }
  this.disconnectPlayer = (socket) => {
      const player = this.findallPlayer(socket.id)
      this.findallPlayer(socket.id).disconnected = 2;
      console.log(this.findallPlayer(socket.id).username + '掉线');
      if (player.getUsername() == this.host) {
        if (this.allplayers.length > 0) {
          this.host = this.allplayers[0].getUsername();
        }
      }
      if (this.roundInProgress == true) {
        if (this.isStageComplete() && this.allPlayersAllIn() && player.getStatus() != 'Fold') {
          this.step1 = () => {
            return new Promise(resolve => {
              this.dealwithdisconnectwhenallin();
              resolve();
            });
          }
          this.step2 = () => {
            return new Promise(resolve => {
              this.callbackfordisconnect();
              resolve();
            });
          }
          this.step1().then(() => {
            return this.step2();
          });
        } else {
          if (player.getStatus() == 'Their Turn') {
            setTimeout(() => this.fold(socket), 10000)
          }
        }
      }
      else
      this.emitallPlayers('playerDisconnected', {player: player.getUsername()});
      this.rerender();
  };
  this.getCurrentPot = () => {
    if (this.roundData.bets == undefined || this.roundData.bets.length == 0)
      return 0;
    else {
      let sum = 0;
      for (let i = 0; i < this.roundData.bets.length; i++) {
        sum += this.roundData.bets[i].reduce(
            (acc, curr) =>
                curr.bet != 'Buy-in' && curr.bet != 'Fold'
                    ? acc + curr.bet
                    : acc + 0,
            0
        );
      }
      return this.foldPot + sum;
    }
  };
  this.reconnectPlayerChangeSocket = (name,socket) =>{
    for (let pn = 0; pn < this.getNumallPlayers(); pn++) {
      if (this.allplayers[pn].getUsername() === name ) {
        this.allplayers[pn].socket = socket;
        this.allplayers[pn].disconnected = 1;
        console.log(this.allplayers[pn]+'重新连接')
      }
    }
    for (let pn = 0; pn < this.getNumPlayers(); pn++) {
      if (this.players[pn].getUsername() === name ) {
        this.players[pn].socket = socket;
        this.players[pn].emit('dealt', {
          currBet: this.getCurrentTopBet(),
          username: this.players[pn].getUsername(),
          cards: this.players[pn].cards,
          players: this.players.map((p) => {
            return p.username;
          }),
        });
      }
    }
    this.rerender()
  }
  this.getPlayersArray = () => {
    return this.allplayers.map((p) => {
      return p.getUsername();
    });
  };
  this.getPlayerBetInStage = (player) => {
    if (
        this.roundData.bets == undefined ||
        this.roundData.bets.length == 0 ||
        this.getCurrentRoundBets() == undefined
    )
      return 0;
    const stageData = this.getCurrentRoundBets();
    let totalBetInStage = 0;

    for (let j = 0; j < stageData.length; j++) {
      if (
          stageData[j].player == player.getUsername() &&
          stageData[j].bet != 'Buy-in' &&
          stageData[j].bet != 'Fold'
      ) {
        totalBetInStage += stageData[j].bet;
        break;
      }
    }
    return totalBetInStage;
  };

  this.getCurrentTopBet = () => {
    if (this.roundData.bets == undefined || this.roundData.bets.length == 0)
      return 0;
    else {
      let maxBet = 0;
      for (let i = 0; i < this.players.length; i++) {
        maxBet = Math.max(maxBet, this.getPlayerBetInStage(this.players[i]));
      }
      return maxBet;
    }
  };

  this.getStageName = () => {
    if (this.roundData.bets.length == 1) {
      return 'Pre-Flop';
    } else if (this.roundData.bets.length == 2) {
      return 'Flop';
    } else if (this.roundData.bets.length == 3) {
      return 'Turn';
    } else if (this.roundData.bets.length == 4) {
      return 'River';
    } else {
      return '未开始';
    }
  };

  this.playerIsChecked = (playr) => {
    if (this.roundData.bets) {
      const bets = this.getCurrentRoundBets() || [];
      return bets.some((a) => a.player == playr.getUsername() && a.bet == 0);
    }
  };

  this.findFirstToGoPlayer = () => {
    if (
        !this.players[this.roundData.smallBlind] ||
        this.players[this.roundData.smallBlind].getStatus() == 'Fold' ||
        this.players[this.roundData.smallBlind].allIn
    ) {
      let index = this.roundData.smallBlind;
      do {
        index = index + 1 >= this.players.length ? 0: index + 1;
      } while (
          this.players[index].getStatus() == 'Fold' ||
          this.players[index].allIn
          );
      return index;
    } else {
      return this.roundData.smallBlind;
    }
  };

  this.getNonFoldedPlayer = () => {
    let numNonFolds = 0;
    let nonFolderPlayer;
    for (let i = 0; i < this.getNumPlayers(); i++) {
      if (this.players[i].getStatus() != 'Fold') {
        numNonFolds++;
        nonFolderPlayer = this.players[i];
      }
    }
    return [numNonFolds, nonFolderPlayer];
  };

  this.updateStage = () => {
    for (let i = 0; i < this.players.length; i++) {
      if (
          i === this.findFirstToGoPlayer() &&
          this.players[i].getStatus() !== 'Fold'
      ) {
        this.players[i].setStatus('Their Turn');
      } else if (this.players[i].getStatus() !== 'Fold') {
        this.players[i].setStatus('');
      }
    }
    this.roundData.bets.push([]);
    this.EmitQuickQcheckOrFold();
  };

  this.moveOntoNextPlayer = () => {
    let handOver = false;
    if (this.isStageComplete()) {
      this.log('stage complete');
      // stage-by-stage logic.
      // check if everyone folded but one
      const [numNonFolds, nonFolderPlayer] = this.getNonFoldedPlayer();
      if (numNonFolds == 1) {
        // everyone folded, start new round, give pot to player
        this.log('everyone folded except one');
        console.log('everyone folded except one-check')
        nonFolderPlayer.money = this.getCurrentPot() + nonFolderPlayer.money;
        this.endHandAllFold(nonFolderPlayer.getUsername());
        handOver = true;
      } else {
        if (this.roundData.bets.length == 1) {
          this.community.push(this.deck.dealRandomCard());
          this.community.push(this.deck.dealRandomCard());
          this.community.push(this.deck.dealRandomCard());
          this.updateStage();//重置‘their turn‘状态
        } else if (this.roundData.bets.length == 2) {
          this.community.push(this.deck.dealRandomCard());
          this.updateStage();
        } else if (this.roundData.bets.length == 3) {
          this.community.push(this.deck.dealRandomCard());
          this.updateStage();
        } else if (this.roundData.bets.length == 4) {
          handOver = true;
          const roundResults = this.evaluateWinners();
          for (playerResult of roundResults.playersData) {
            playerResult.player.setStatus(playerResult.hand.name);
          }
          const winningData = this.distributeMoney(roundResults);
          this.revealCards(winningData.filter((a) => a.winner));
        } else {
          this.log('This stage of the round is INVALID!!');
        }
      }
    } else {
      this.log('stage not complete');
      //check if everyone folded except one player
      const [numNonFolds, nonFolderPlayer] = this.getNonFoldedPlayer();
      if (!handOver && numNonFolds == 1) {
        // everyone folded, start new round, give pot to player
        this.log('everyone folded except one');
        console.log('everyone folded except one')
        nonFolderPlayer.money = this.getCurrentPot() + nonFolderPlayer.money;
        this.endHandAllFold(nonFolderPlayer.getUsername());
        handOver = true;
      } else {
        let currTurnIndex = 0;
        //check if move just made was a fold
        if (this.lastMoveParsed.move == 'Fold') {
          currTurnIndex = this.players.findIndex(
              (p) => p === this.lastMoveParsed.player
          );
          this.lastMoveParsed = {move: '', player: ''};
        } else {
          currTurnIndex = this.players.findIndex(
              (p) => p.getStatus() === 'Their Turn'
          );
          this.players[currTurnIndex].setStatus('');
        }
        let count = 0;
        do {
          currTurnIndex = currTurnIndex +1 >= this.players.length ? 0 : currTurnIndex + 1;
          count++;
        } while (
            (this.players[currTurnIndex].getStatus() == 'Fold'
                || this.players[currTurnIndex].allIn)
            && count < Object.keys(this.players).length * 2 // Avoid infinite loop, allow search twice on all players
            );
        this.players[currTurnIndex].setStatus('Their Turn');
      }
    }
    if (!handOver) {
      this.log('RERENDERING');
      this.rerender();
      let currTurnIndex = this.players.findIndex(
          (p) => p.getStatus() === 'Their Turn'
      );
      if(this.players.length > 0) this.players[currTurnIndex].emit('TimeToGo',{})
      if (this.findName(this.players[currTurnIndex].username).disconnected == 2){
        this.fold(this.players[currTurnIndex].socket)
      }
    }
    this.timecooldown();
  };
  this.getPlayerBetInStageNum = (player, stageNum) => {
    if (
        this.roundData.bets == undefined ||
        this.roundData.bets.length == 0 ||
        this.roundData.bets[stageNum - 1] == undefined
    )
      return 0;
    const stageData = this.roundData.bets[stageNum - 1];
    let totalBetInStage = 0;

    for (let j = 0; j < stageData.length; j++) {
      if (
          stageData[j].player == player.getUsername() &&
          stageData[j].bet != 'Buy-in' &&
          stageData[j].bet != 'Fold'
      )
        totalBetInStage += stageData[j].bet;
    }
    return totalBetInStage;
  };

  this.getTotalBetsInStageNum = (stageNum) => {
    if (
        this.roundData.bets == undefined ||
        this.roundData.bets.length == 0 ||
        this.roundData.bets[stageNum - 1] == undefined
    )
      return 0;
    const stageData = this.roundData.bets[stageNum - 1];
    let totalBetInStage = 0;

    for (let j = 0; j < stageData.length; j++) {
      if (stageData[j].bet != 'Buy-in' && stageData[j].bet != 'Fold')
        totalBetInStage += stageData[j].bet;
    }
    return totalBetInStage;
  };

  this.getTotalInvested = (player) => {
    return (
        this.getPlayerBetInStageNum(player, 1) +
        this.getPlayerBetInStageNum(player, 2) +
        this.getPlayerBetInStageNum(player, 3) +
        this.getPlayerBetInStageNum(player, 4)
    );
  };

  this.calculateMoney = (winnerPot, players) => {
    let playerInvestments = [...players];
    while (playerInvestments.length > 1) {
      const sortedByInvested = playerInvestments.sort((a, b) =>
          a.invested < b.invested ? -1 : 1
      );
      const minStack = sortedByInvested[0].invested;
      winnerPot += minStack * playerInvestments.length;
      for (p of playerInvestments) {
        p.invested -= minStack;
      }
      const sortedByHandStrength = playerInvestments.sort((a, b) =>
          a.handStrength > b.handStrength ? -1 : 1
      );
      const maxHand = sortedByHandStrength[0].handStrength;
      const winners = playerInvestments.filter(
          (p) => p.handStrength === maxHand && p.live
      );
      for (p of winners) {
        p.result += winnerPot / winners.length;
      }
      playerInvestments = playerInvestments.filter((p) => p.invested > 0);
      winnerPot = 0;
    }

    if (playerInvestments.length === 1) {
      let p = playerInvestments[0];
      p.result += winnerPot + p.invested;
    }
  };

  this.distributeMoney = (result) => {
    let playerInvestments = this.players.map((p) => {
      const winData = result.winnerData.find((w) => w.player === p);
      const invested = this.getTotalInvested(p);
      return {
        player: p,
        invested: invested,
        originalInvested: invested,
        handStrength: winData ? winData.rank : -1,
        result: -invested,
        live: p.getStatus() !== 'Fold',
        winner: false,
        gain: 0,
      };
    });
    let pot = this.foldPot;
    this.calculateMoney(pot, playerInvestments);

    for (p of playerInvestments) {
      p.gain = p.originalInvested + p.result;
      p.player.money += p.gain;
      if (p.gain > 0) {
        p.winner = true;
      }
    }
    return playerInvestments;
  };

  this.evaluateWinners = () => {
    let handArray = [];
    let playerArray = [];
    for (let i = 0; i < this.players.length; i++) {
      if (this.players[i].getStatus() != 'Fold') {
        let h = Hand.solve(
            this.convertCardsFormat(this.players[i].cards.concat(this.community))
        );
        handArray.push(h);
        playerArray.push({ player: this.players[i], hand: h });
      }
    }
    const winners = Hand.winners(handArray);

    let winnerData = [];
    if (Array.isArray(winners)) {
      for (playerHand of playerArray) {
        for (winner of winners) {
          let winnerArray = winner.toString().split(', ');
          if (
              this.arraysEqual(playerHand.hand.cards.sort(), winnerArray.sort())
          ) {
            winnerData.push({
              player: playerHand.player,
              rank: playerHand.hand.rank,
              handTitle: playerHand.hand.name,
            });
            break;
          }
        }
      }
    } else {
      this.log('fatal error: winner cannot be calculated');
    }
    const res = { winnerData: winnerData, playersData: playerArray };
    return res;
  };

  this.arraysEqual = (a, b) => {
    if (a === b) return true;
    if (a == null || b == null) return false;
    if (a.length != b.length) return false;

    for (let i = 0; i < a.length; ++i) {
      if (a[i] != b[i]) return false;
    }
    return true;
  };

  this.convertCardsFormat = (arr) => {
    let res = [];
    for (let i = 0; i < arr.length; i++) {
      let str = '';
      let value = arr[i].getValue();
      let suit = arr[i].getSuit();
      if (value == 10) {
        str += 'T';
      } else {
        str += value.toString();
      }
      if (suit == '♠') str += 's';
      else if (suit == '♥') str += 'h';
      else if (suit == '♦') str += 'd';
      else if (suit == '♣') str += 'c';
      res.push(str);
    }
    return res;
  };
//endhand和reveal的rerender需要重新调试
  this.endHandAllFold = (username) => {
    this.log('endhandallfold' + this.players);
    this.roundInProgress = false;
    let cardData = [];
    let playerDataforone = [];
    for (let i = 0; i < this.players.length; i++) {
      cardData.push({
        index : i,
        username: this.players[i].getUsername(),
        money: this.players[i].getMoney(),
        text: this.players[i].getStatus(),
      });
    }
    for (let pn = 0; pn < this.getNumPlayers(); pn++) {
      playerDataforone = cardData.filter((p) => p.index != pn)
      for (let i = 0; i < playerDataforone.length; i++) {
        if (playerDataforone[i].index < pn) playerDataforone[i].index += this.players.length;
      }
      playerDataforone = playerDataforone.sort((a, b) => a.index < b.index ? -1 : 1)
      this.players[pn].emit('endHand', {
        winner: username,
        folded: this.players[pn].getUsername() != username ? 'Fold' : '',
        username: this.players[pn].getUsername(),
        pot: this.getCurrentPot(),
        money: this.players[pn].getMoney(),
        cards: playerDataforone,
        bets: this.roundData.bets,
      });
    }
    for (let pn = 0; pn < this.getNumallPlayers(); pn++) {
      if (!this.players.includes(this.allplayers[pn])) {
        this.allplayers[pn].emit('endHand', {
          winner: username,
          folded: '',
          username: this.allplayers[pn].getUsername(),
          pot: this.getCurrentPot(),
          money: this.allplayers[pn].getMoney(),
          cards: cardData,
          bets: this.roundData.bets,
        });
      }
      }
    this.emitPlayers('TimeToGo',{})
    this.stoptimecooldown();
    setTimeout(() => this.emitallPlayers('playnext',{}), 5000);
  };

  this.revealCards = (winners) => {
    this.roundInProgress = false;
    let cardData = [];
    let playerDataforone = [];
    for (let i = 0; i < this.players.length; i++) {
      const winData = winners.find((w) => w.player === this.players[i]);
      cardData.push({
        index:i,
        username: this.players[i].getUsername(),
        cards: this.players[i].cards,
        hand: this.players[i].getStatus(),
        folded: this.players[i].getStatus() == 'Fold',
        money: this.players[i].getMoney(),
        buyIns: this.players[i].buyIns,
        gain: winData ? winData.gain : null,
      });
    }
    const winnersUsernames = winners
        .map((a) => a.player.getUsername())
        .toString();
    for (let pn = 0; pn < this.getNumPlayers(); pn++) {
      playerDataforone = cardData.filter((p) => p.index != pn)
      for (let i = 0; i < playerDataforone.length; i++) {
        if (playerDataforone[i].index < pn) playerDataforone[i].index += this.players.length;
      }
      playerDataforone = playerDataforone.sort((a, b) => a.index < b.index ? -1 : 1)
      this.players[pn].emit('reveal', {
        username: this.players[pn].getUsername(),
        money: this.players[pn].getMoney(),
        cards: playerDataforone,
        bets: this.roundData.bets,
        winners: winnersUsernames,
        hand: this.players[pn].getStatus(),
      });
    }
    for (let pn = 0; pn < this.getNumallPlayers(); pn++) {
      if (!this.players.includes(this.allplayers[pn])) {
        this.allplayers[pn].emit('reveal', {
          username: this.allplayers[pn].getUsername(),
          money: this.allplayers[pn].getMoney(),
          cards: cardData,
          bets: this.roundData.bets,
          winners: winnersUsernames,
          hand: this.allplayers[pn].getStatus(),
        });
      }
      }
    this.stoptimecooldown();
    setTimeout(() => this.emitallPlayers('playnext',{}), 5000);
  };

  this.allPlayersAllIn = () => {
    let participatingPlayers = 0;
    let allinPlayers = 0;
    for (player of this.players) {
      if (!player.allIn && player.getStatus() != 'Fold') participatingPlayers++;
      if (player.allIn ) allinPlayers++;
    }
    return ( participatingPlayers < 1 || (allinPlayers>0 && participatingPlayers == 1));
  };

  this.isStageComplete = () => {
    let allPlayersPresent = false;
    let numUnfolded = 0;
    for (let i = 0; i < this.players.length; i++) {
      if (this.players[i].status != 'Fold' && !this.players[i].allIn)
        numUnfolded++;
    }
    const currRound = this.getCurrentRoundBets();
    if (this.roundData.bets.length == 1) {
      allPlayersPresent =
          currRound.filter((a) => a.bet != 'Fold').length >= numUnfolded &&
          this.bigBlindWent;
    } else {
      allPlayersPresent =
          currRound.filter((a) => a.bet != 'Fold').length >= numUnfolded;
    }
    this.log('all players present ' + allPlayersPresent);
    let allPlayersCall = true;
    for (player of this.players) {
      if (
          player.getStatus() != 'Fold' &&
          this.getPlayerBetInStage(player) != this.getCurrentTopBet() &&
          !player.allIn
      ) {
        allPlayersCall = false;
        break;
      }
    }
    this.log('all players call ' + allPlayersCall);
    return allPlayersPresent && allPlayersCall;
  };

  this.setCardsPerPlayer = (numCards) => {
    this.cardsPerPlayer = numCards;
  };

  this.getHostName = () => {
    return this.host;
  };



  this.getCode = () => {
    return this.gameName;
  };



  this.dealCards = () => {
    console.log('发牌')
    this.deck.shuffle();
    for (let pn = 0; pn < this.getNumPlayers(); pn++) {
      this.players[pn].cards = [];
      for (let i = 0; i < this.cardsPerPlayer; i++) {
        this.players[pn].addCard(this.deck.dealRandomCard());
      }
    }

    this.refreshCards();
  };

  this.refreshCards = function () {
    for (let pn = 0; pn < this.getNumPlayers(); pn++) {
      this.players[pn].cards.sort((a, b) => {
        return a.compare(b);
      });

      this.players[pn].emit('dealt', {
        currBet: this.getCurrentTopBet(),
        username: this.players[pn].getUsername(),
        cards: this.players[pn].cards,
        players: this.players.map((p) => {
          return p.username;
        }),
      });
    }
  };


  this.checkBigBlindWent = (socket) => {
    if (
        this.findPlayer(socket.id).blindValue == 'Big Blind' &&
        this.roundData.bets.length == 1
    ) {
      this.bigBlindWent = true;
    }
  };

  this.getCurrentRoundBets = () => {
    return this.roundData.bets[this.roundData.bets.length - 1];
  };

  this.setCurrentRoundBets = (bets) => {
    return (this.roundData.bets[this.roundData.bets.length - 1] = bets);
  };

  this.fold = (socket) => {
    this.checkBigBlindWent(socket);
    if (this.findPlayer(socket.id).getStatus() == 'Their Turn') {
      const player = this.findPlayer(socket.id);
      let preFoldBetAmount = 0;

      let roundDataStage = this.getCurrentRoundBets().find(
          (a) => a.player == player.getUsername()
      );
      if (roundDataStage != undefined && roundDataStage.bet != 'Fold') {
        preFoldBetAmount += roundDataStage.bet;
      }
      player.setStatus('Fold');
      this.foldPot = this.foldPot + preFoldBetAmount;
      if (
          this.getCurrentRoundBets().some((a) => a.player == player.getUsername())
      ) {
        this.setCurrentRoundBets(
            this.getCurrentRoundBets().map((a) =>
                a.player == player.getUsername()
                    ? {player: player.getUsername(), bet: 'Fold'}
                    : a
            )
        );
      } else {
        this.getCurrentRoundBets().push({
          player: player.getUsername(),
          bet: 'Fold',
        });
      }
      this.lastMoveParsed = {move: 'Fold', player: player};
      if (this.isStageComplete() && this.allPlayersAllIn()) {
        this.askfortheinsurance()
      } else {
        this.moveOntoNextPlayer();
      }
      return true;
    }
  };

  this.call = (socket) => {
    this.checkBigBlindWent(socket);
    const player = this.findPlayer(socket.id);
    let currBet = this.getPlayerBetInStage(player);
    const topBet = this.getCurrentTopBet();
    if (currBet === 0) {
      if (
          this.getCurrentRoundBets().some((a) => a.player == player.getUsername())
      ) {
        if (player.getMoney() - topBet <= 0) {
          this.setCurrentRoundBets(
              this.getCurrentRoundBets().map((a) =>
                  a.player == player.username
                      ? { player: player.getUsername(), bet: player.getMoney() }
                      : a
              )
          );
          player.money = 0;
          player.allIn = true;
        } else {
          this.setCurrentRoundBets(
              this.getCurrentRoundBets().map((a) =>
                  a.player == player.username
                      ? { player: player.getUsername(), bet: topBet }
                      : a
              )
          );
          player.money = player.money - topBet;
        }
      } else {
        if (player.getMoney() - topBet <= 0) {
          this.getCurrentRoundBets().push({
            player: player.getUsername(),
            bet: player.getMoney(),
          });
          player.money = 0;
          player.allIn = true;
        } else {
          this.getCurrentRoundBets().push({
            player: player.getUsername(),
            bet: topBet,
          });
          player.money = player.money - topBet;
        }
      }
      if (this.isStageComplete() && this.allPlayersAllIn()) {
        this.askfortheinsurance()
      } else {
        this.moveOntoNextPlayer();
      }
      return true;
    } else {
      if (
          this.getCurrentRoundBets().some((a) => a.player == player.getUsername())
      ) {
        if (player.getMoney() + currBet - topBet <= 0) {
          this.setCurrentRoundBets(
              this.getCurrentRoundBets().map((a) =>
                  a.player == player.username
                      ? {
                        player: player.getUsername(),
                        bet: player.getMoney() + currBet,
                      }
                      : a
              )
          );
          player.money = 0;
          player.allIn = true;
          if (this.isStageComplete() && this.allPlayersAllIn()) {
            this.askfortheinsurance()
          } else {
            this.moveOntoNextPlayer();
          }
        } else {
          this.setCurrentRoundBets(
              this.getCurrentRoundBets().map((a) =>
                  a.player == player.username
                      ? { player: player.getUsername(), bet: topBet }
                      : a
              )
          );
          player.money = player.money - (topBet - currBet);
          if (this.isStageComplete() && this.allPlayersAllIn()) {
            this.askfortheinsurance()
          } else {
            this.moveOntoNextPlayer();
          }
        }
        return true;
      } else {
        this.log('this should not happen');
      }
    }
  };

  this.bet = (socket, bet) => {
    this.checkBigBlindWent(socket);
    if (bet >= this.bigBlind) {
      const player = this.findPlayer(socket.id);
      if (player.getMoney() - bet >= 0) {
        this.setCurrentRoundBets(
            this.getCurrentRoundBets().filter(
                (a) => a.player != player.getUsername()
            )
        );
        this.getCurrentRoundBets().push({
          player: player.getUsername(),
          bet: bet,
        });
        player.money = player.money - bet;
        if (player.money == 0) player.allIn = true;
        this.moveOntoNextPlayer();
        return true;
      }
    }
  };

  this.check = (socket) => {
    this.checkBigBlindWent(socket);
    let currBet = 0;
    const player = this.findPlayer(socket.id);
    if (
        this.getCurrentRoundBets().find(
            (a) => a.player == player.getUsername()
        ) != undefined
    ) {
      currBet = this.getCurrentRoundBets().find(
          (a) => a.player == player.getUsername()
      ).bet;
      this.setCurrentRoundBets(
          this.getCurrentRoundBets().map((a) =>
              a.player == player.getUsername()
                  ? { player: player.getUsername(), bet: currBet }
                  : a
          )
      );
    } else {
      this.getCurrentRoundBets().push({
        player: player.getUsername(),
        bet: currBet,
      });
    }
    this.moveOntoNextPlayer();
    return true;
  };

  this.raise = (socket, bet) => {
    this.checkBigBlindWent(socket);
    const topBet = this.getCurrentTopBet();
    const player = this.findPlayer(socket.id);
    const currBet = this.getPlayerBetInStage(player);
    const moneyToRemove = bet - currBet;
    if (
        moneyToRemove > 0 &&
        bet >= topBet &&
        player.getMoney() - moneyToRemove >= 0
    ) {
      if (currBet === 0) {
        this.setCurrentRoundBets(
            this.getCurrentRoundBets().filter(
                (a) => a.player != player.getUsername()
            )
        );
        this.getCurrentRoundBets().push({
          player: player.getUsername(),
          bet: bet,
        });
      } else {
        this.setCurrentRoundBets(
            this.getCurrentRoundBets().map((a) =>
                a.player == player.getUsername()
                    ? { player: player.getUsername(), bet: bet }
                    : a
            )
        );
      }
      player.money -= moneyToRemove;
      if (player.money == 0) player.allIn = true;
      if (this.isStageComplete() && this.allPlayersAllIn()) {
        this.askfortheinsurance()
      } else {
        this.moveOntoNextPlayer();
      }
      return true;
    }
  };
  this.quickbet=(socket,betq)=>{
    let bet
    const player = this.findPlayer(socket.id);
    if (Math.ceil(this.getCurrentPot()*betq)>player.getMoney()){
      bet = player.getMoney();
    }else{
      bet =Math.ceil(this.getCurrentPot()*betq);
    }
    //let bet = Math.ceil(this.getCurrentPot()*betq);
    this.checkBigBlindWent(socket);
    // if (bet >= this.bigBlind){
    if (player.getMoney() - bet >= 0) {
      this.setCurrentRoundBets(
          this.getCurrentRoundBets().filter(
              (a) => a.player != player.getUsername()
          )
      );
      this.getCurrentRoundBets().push({
        player: player.getUsername(),
        bet: bet,
      });
      player.money = player.money - bet;
      if (player.money == 0) player.allIn = true;
      if (this.isStageComplete() && this.allPlayersAllIn() ) {
        this.askfortheinsurance()
      }
      else {
        this.moveOntoNextPlayer();
      }
      return true;
    }
    // }
  };
  this.quickraise = (socket, betq) => {
    this.checkBigBlindWent(socket);
    const topBet = this.getCurrentTopBet();
    const player = this.findPlayer(socket.id);
    const currBet = this.getPlayerBetInStage(player);
    let bet;
    if (Math.ceil(topBet*betq)>player.getMoney()+currBet){
      bet = player.getMoney()+currBet;
    }else{
      bet =Math.ceil(topBet*betq);
    }
    const moneyToRemove = bet - currBet;
    if (
        moneyToRemove > 0 &&
        bet >= topBet &&
        player.getMoney() - moneyToRemove >= 0
    ) {
      if (currBet === 0) {
        this.setCurrentRoundBets(
            this.getCurrentRoundBets().filter(
                (a) => a.player != player.getUsername()
            )
        );
        this.getCurrentRoundBets().push({
          player: player.getUsername(),
          bet: bet,
        });
      } else {
        this.setCurrentRoundBets(
            this.getCurrentRoundBets().map((a) =>
                a.player == player.getUsername()
                    ? {player: player.getUsername(), bet: bet}
                    : a
            )
        );
      }
      player.money -= moneyToRemove;
      if (player.money == 0) player.allIn = true;
      if (this.isStageComplete() && this.allPlayersAllIn() ) {
        this.askfortheinsurance()
      }
      else {
        this.moveOntoNextPlayer();
      }
      return true;
    }
  };

  this.getPossibleMoves = (socket) => {
    const player = this.findPlayer(socket.id);
    const playerBet = this.getPlayerBetInStage(player);
    const topBet = this.getCurrentTopBet();
    let possibleMoves = {
      fold: 'yes',
      check: 'yes',
      bet: 'yes',
      call: topBet,
      raise: 'yes',
    };
    if (player.getStatus() == 'Fold') {
      this.log('Error: Folded players should not be able to move.');
    }
    if (topBet != 0) {
      possibleMoves.bet = 'no';
      possibleMoves.check = 'no';
      if (
          player.blindValue == 'Big Blind' &&
          !this.bigBlindWent &&
          topBet == this.bigBlind
      )
        possibleMoves.check = 'yes';
    } else {
      possibleMoves.raise = 'no';
    }
    if (topBet <= playerBet) {
      possibleMoves.call = 'no';
    }
    if (topBet >= player.getMoney() + playerBet) {
      possibleMoves.raise = 'no';
      possibleMoves.call = 'all-in';
    }
    return possibleMoves;
  };
  this.EmitQuickQcheckOrFold= ()=> {
    let havenotbetplayers =  this.players.filter(
        (p) => p.getStatus ()!= 'Fold' && p.allIn == false && p.getStatus() != 'Their Turn'
    );
    for (let i =0 ; i<havenotbetplayers.length ;i ++) {
      havenotbetplayers[i].emit('CheckOrFold', {})
    }
  }
  this.EmitQuickCall= ()=> {
    this.waitcall = [];
    // this.waitcheckfold = [];
    let havenotbetplayers =  this.players.filter(
        (p) => p.getStatus ()!= 'Fold' && p.allIn == false && p.getStatus() != 'Their Turn' &&
            this.getPlayerBetInStage(p) < this.getCurrentTopBet());
    for (let i =0 ; i<havenotbetplayers.length ;i ++) {
      havenotbetplayers[i].emit('quickcall', {call:this.getCurrentTopBet()})
    }
  }


//   保险相关类


  this.revealCardsforallin = (winners) => {
    this.log('reveal');
    this.roundInProgress = false;
    let cardData = [];
    for (let i = 0; i < this.players.length; i++) {
      const winData = winners.find((w) => w.player === this.players[i]);
      cardData.push({
        username: this.players[i].getUsername(),
        cards: this.players[i].cards,
        hand: this.players[i].getStatus(),
        folded: this.players[i].getStatus() == 'Fold',
        money: this.players[i].getMoney(),
        buyIns: this.players[i].buyIns,
        gain: winData ? winData.gain : null,
      });
    }
    const winnersUsernames = winners
        .map((a) => a.player.getUsername())
        .toString();
    for (let pn = 0; pn < this.getNumPlayers(); pn++) {
      this.players[pn].emit('revealforallin', {
        username: this.players[pn].getUsername(),
        money: this.players[pn].getMoney(),
        cards: cardData,
        bets: this.roundData.bets,
        winners: winnersUsernames,
        hand: this.players[pn].getStatus(),
      });
    }
  };
  this. getCurrentMinBetForAllin = () =>{
    let playerInvestments = this.players.map((p) => {
      const invested = this.getTotalInvested(p);
      return {
        player: p,
        invested: invested,
        originalInvested: invested,
        result: -invested,
        live: p.getStatus() !== 'Fold',
        disconnect:p.disconnected,
        gain: 0,
      };
    });
    playerInvestments = playerInvestments.filter((a) => a.disconnect == 0);
    const sortedByInvested = playerInvestments.sort((a, b) =>
        a.invested < b.invested ? -1 : 1
    );
    const minStack = sortedByInvested[0].invested;
    return minStack
  }
  this.getwinnertempt = () =>{
    let handArray = [];
    let playerArray = [];
    for (let i = 0; i < this.players.length; i++) {
      if (this.players[i].getStatus() != 'Fold') {
        let h = Hand.solve(
            this.convertCardsFormat(this.players[i].cards.concat(this.community))
        );
        handArray.push(h);
        playerArray.push({player: this.players[i], hand: h});
      }
    }
    const winners = Hand.winners(handArray);
    let winnerData = [];
    if (Array.isArray(winners)) {
      for (playerHand of playerArray) {
        for (winner of winners) {
          let winnerArray = winner.toString().split(', ');
          if (this.arraysEqual(playerHand.hand.cards.sort(), winnerArray.sort())
          ) {
            winnerData.push(playerHand.player.getUsername());
            break;
          }
        }
      }
    }
    return winnerData
  }
  this.calodds = () => {
    let outs = [];//计算反超牌数量
    let winnerbefore = this.getwinnertempt();//评估当前赢家

    for (let i = 0; i < this.deck.cardsforIns.length; i++) {
      this.community.push(this.deck.cardsforIns[i]);
      let winnera = this.getwinnertempt()
      if (winnera.toString()!= winnerbefore.toString() && winnera.length == 1 ) {
        outs.push(this.deck.cardsforIns[i]);//如果赢家变化，该张牌进入out[],且不分池
      }
      this.community.splice(this.community.length - 1, 1);//将该张牌从桌上反回牌库
    }
    for (let k =1 ; k < outs.length; k ++) {
      for (let i = 0; i < this.players.length; i++) {
        if (this.players[i].getStatus() != 'Fold') {
          for (let j = 0; j < this.players[i].cards.length; j++) {
            if (this.convertCardsFormat(outs)[k] == this.convertCardsFormat(this.players[i].cards)[j]) {
              outs.splice(k, 1)
              k = k - 1
            }
            // outs = outs.filter((a) =>this.convertCardsFormat(a) != this.convertCardsFormat(this.players[i].cards)[j] )
          }
        }
      }
    }
    for (let i = 0; i < this.players.length; i++) {
      if (this.players[i].getStatus() != 'Fold') {
        for (let j = 0; j < this.players[i].cards.length; j++) {
          if (this.convertCardsFormat(outs)[0] == this.convertCardsFormat(this.players[i].cards)[j]){
            outs.splice(0, 1)
          }
        }
      }
    }
    let odds; //对应不同反超牌数量计算赔率
    if (outs.length == 0) {
      odds = 100
    }
    else if (outs.length == 1) {
      odds = 29
    }
    else if (outs.length == 2) {
      odds = 15
    }
    else if (outs.length == 3) {
      odds = 10
    }
    else if (outs.length == 4) {
      odds = 7
    }
    else if (outs.length == 5) {
      odds = 6
    }
    else if (outs.length == 6) {
      odds = 4.5
    }
    else if (outs.length == 7) {
      odds = 3.5
    }
    else if (outs.length == 8) {
      odds = 3
    }
    else if (outs.length == 9) {
      odds = 2.8
    }
    else if (outs.length == 10) {
      odds = 2.5
    }
    else if (outs.length == 11) {
      odds = 2.3
    }
    else if (outs.length == 12) {
      odds = 2
    }
    else if (outs.length == 13) {
      odds = 1.8
    }
    else if (outs.length == 14) {
      odds = 1.5
    }
    else {
      odds = 0.1
    }
    // console.log(this.convertCardsFormat(outs));
    return {winnernow:winnerbefore,outs:outs,odds:odds} //反回「当前赢家、反超牌、赔率」
  }
  this.rerenderforallin = () =>{
    this.emitPlayers('rerenderforallin', {
      community: this.community})
  }
  this.buyInsurance = (socket)=>{
    const player = this.findPlayer(socket.id);
    const odd =this.calodds().odds
    let insurancepot =  this.getTotalInvested(player)-this.getPlayerBetInStage(player)+this.getCurrentMinBetForAllin();
    this.community.push(this.deck.dealRandomCard());
    this.flopcard ++;
    if (this.roundData.bets.length>1){
      this.roundData.bets.push([]);
    }
    //买保险后的赔付和结算，需要新建保险账户

    // for (let i =0 ; i <this.calodds().outs.length; i ++){
    //   if (this.calodds().outs[i] == this.community[this.community.length - 1]) { //发出outs 赔付
    //     player.money = player.money + insurancepot;
    //     this.insurance = this.insurance - insurancepot;
    //   } else {
    //     this.players[i].money = this.players[i].money - Math.ceil (insurancepot/ this.calodds().odds); //未发出outs
    //     this.insurance = this.insurance + Math.ceil (insurancepot/ this.calodds().odds);
    //     //console.log(this.insurance)
    //   }
    // }
    let winnera = this.getwinnertempt()
    if (winnera!= player.getUsername()&& winnera.length == 1 ) { //独赢玩家变价，即发出out
      player.money = player.money + insurancepot;
      this.insurance = this.insurance - insurancepot;
      console.log('赔付'+player.money)
    } else {
      player.money = player.money - Math.ceil (insurancepot/ odd); //未发出outs
      this.insurance = this.insurance + Math.ceil (insurancepot/ odd);
      //console.log(this.insurance)
      console.log('未赔付'+player.money)
    }
    this.rerender();
    this.askfortheinsurance();

  }
  this.Insuraisnotbought=()=>{ //不买 直接发牌
    this.community.push(this.deck.dealRandomCard());
    this.flopcard ++;
    if (this.roundData.bets.length>1){
      this.roundData.bets.push([]);
    }
    this.rerender();
    this.askfortheinsurance();
  }
  this.askfortheinsurance = () =>{
    this.stoptimecooldown();
    const [numNonFolds, nonFolderPlayer] = this.getNonFoldedPlayer();
    const roundResults = this.evaluateWinners();
    for (playerResult of roundResults.playersData) {
      playerResult.player.setStatus(playerResult.hand.name);
    }
    this.rerender();
    this.revealCardsforallin(roundResults.winnerData.filter((a) => a.winner));
    if (numNonFolds > 1) {
      this.log(' all players all in');
      const win = this.calodds().winnernow[0];
      if (this.roundData.bets.length == 1) {
        if (this.calodds().winnernow.length == 1 && this.findName(win).disconnected == 0  ) { // 计算当前赢家、下张牌发出来的反超概率以及反超牌张数
          if (this.flopcard < 5) {
            this.emitPlayers('closebutton', {})
            for (let i = 0; i < this.players.length; i++) {
              if (this.players[i].getUsername() == this.calodds().winnernow) {
                let reinsurancepot =   Math.ceil ((this.getTotalInvested(this.players[i])-this.getPlayerBetInStage(this.players[i])+this.getCurrentMinBetForAllin())/ this.calodds().odds);//根据投入推荐购买金额
                this.players[i].emit('Insstart', { //向玩家emit保险相关字段，在app.js里监听，并向当前赢家emit保险页面，在main.js里弹出页面，并根据点击emit不同字段，在app.js里监听，并emit给玩家，最终调用ganme.insubought=()函数，修改goon，Insisbuy的布尔值
                  winner: this.calodds().winnernow,
                  insouts: this.calodds().outs.length,
                  outsdetail:this.convertCardsFormat(this.calodds().outs),
                  insodds: this.calodds().odds,
                  howmuchtobuy: reinsurancepot,
                });
              }
            }
          }
          if (this.flopcard == 5) {
            const roundResults = this.evaluateWinners();
            for (playerResult of roundResults.playersData) {
              playerResult.player.setStatus(playerResult.hand.name);
            }
            const winningData = this.distributeMoney(roundResults);
            this.revealCards(winningData.filter((a) => a.winner));
          }
        } else {
          do {
            this.community.push(this.deck.dealRandomCard());
            this.flopcard++
          }
          while (this.flopcard < 5);
          this.rerender();
          const roundResults = this.evaluateWinners();
          for (playerResult of roundResults.playersData) {
            playerResult.player.setStatus(playerResult.hand.name);
          }
          const winningData = this.distributeMoney(roundResults);
          this.revealCards(winningData.filter((a) => a.winner));
        }
      }
      if (this.roundData.bets.length == 2) {
        if (this.calodds().winnernow.length == 1&& this.findName(win).disconnected == 0 ) { // 计算当前赢家、下张牌发出来的反超概率以及反超牌张数
          let Inspots = Math.floor(this.getCurrentPot() / (this.getNonFoldedPlayer().length + 0.5) / this.calodds().odds);//根据投入推荐购买金额
          this.emitPlayers('closebutton', {})
          for (let i = 0; i < this.players.length; i++) {
            if (this.players[i].getUsername() == this.calodds().winnernow) {
              this.players[i].emit('Insstart', { //向玩家emit保险相关字段，在app.js里监听，并向当前赢家emit保险页面，在main.js里弹出页面，并根据点击emit不同字段，在app.js里监听，并emit给玩家，最终调用ganme.insubought=()函数，修改goon，Insisbuy的布尔值
                winner: this.calodds().winnernow,
                insouts: this.calodds().outs.length,
                insodds: this.calodds().odds,
                howmuchtobuy: Inspots,
              });
            }
          }
        } else {
          this.community.push(this.deck.dealRandomCard());
          this.community.push(this.deck.dealRandomCard());
          this.rerender();
          const roundResults = this.evaluateWinners();
          for (playerResult of roundResults.playersData) {
            playerResult.player.setStatus(playerResult.hand.name);
          }
          const winningData = this.distributeMoney(roundResults);
          this.revealCards(winningData.filter((a) => a.winner));
        }
      }
      if (this.roundData.bets.length == 3) {
        if (this.calodds().winnernow.length == 1&& this.findName(win).disconnected == 0) { // 计算当前赢家、下张牌发出来的反超概率以及反超牌张数
          let Inspots = Math.floor(this.getCurrentPot() / (this.getNonFoldedPlayer().length + 0.5) / this.calodds().odds);//根据投入推荐购买金额
          this.emitPlayers('closebutton', {})
          for (let i = 0; i < this.players.length; i++) {
            if (this.players[i].getUsername() == this.calodds().winnernow) {
              this.players[i].emit('Insstart', { //向玩家emit保险相关字段，在app.js里监听，并向当前赢家emit保险页面，在main.js里弹出页面，并根据点击emit不同字段，在app.js里监听，并emit给玩家，最终调用ganme.insubought=()函数，修改goon，Insisbuy的布尔值
                winner: this.calodds().winnernow,
                insouts: this.calodds().outs.length,
                insodds: this.calodds().odds,
                howmuchtobuy: Inspots,
              });
            }
          }
        } else {
          this.community.push(this.deck.dealRandomCard());
          this.rerender();
          const roundResults = this.evaluateWinners();
          for (playerResult of roundResults.playersData) {
            playerResult.player.setStatus(playerResult.hand.name);
          }
          const winningData = this.distributeMoney(roundResults);
          this.revealCards(winningData.filter((a) => a.winner));
          this.rerender();
        }
      }
      if (this.roundData.bets.length == 4) {
        const roundResults = this.evaluateWinners();
        for (playerResult of roundResults.playersData) {
          playerResult.player.setStatus(playerResult.hand.name);
        }
        const winningData = this.distributeMoney(roundResults);
        this.revealCards(winningData.filter((a) => a.winner));
      }
    }
    else if (numNonFolds == 1){
      this.log('everyone folded except one');
      nonFolderPlayer.money = this.getCurrentPot() + nonFolderPlayer.money;
      this.endHandAllFold(nonFolderPlayer.getUsername());
    } else {
      this.log('everyone folded, no winner');
      const [numFolds, FolderPlayer] = this.getAllFoldPlayer();
      this.endHandAllFold(FolderPlayer.getUsername());
    }
  }
  this.getAllFoldPlayer = ()=>{
    let numFolds = 0;
    let FolderPlayer;
    for (let i = 0; i < this.getNumPlayers(); i++) {
      if (this.players[i].getStatus() == 'Fold') {
        numFolds++;
        FolderPlayer = this.players[i];
      }
    }
    return [numFolds, FolderPlayer];
  };

  //延迟计时条相关类
  this.timecooldown = ()=>{
    this.emitallPlayers ('cooldown',{});
  }
  this.stoptimecooldown = ()=>{
    this.emitallPlayers ('stopcooldown',{});
  }

};

module.exports = Game;
